package com.mongodb.service;

import com.alibaba.fastjson.JSON;
import com.mongodb.BasicDBObject;
import com.mongodb.document.test.*;
import com.mongodb.model.*;
import org.assertj.core.util.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.mapreduce.GroupBy;
import org.springframework.data.mongodb.core.mapreduce.GroupByResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;

import java.util.List;

import static org.springframework.data.domain.Sort.Direction.ASC;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregation;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.project;

@Service
public class TestService {
    @Autowired
    private MongoTemplate mongoTemplate;

    public void addGroupTestList(List<GroupTestCollection> list) {
      //  List<GroupTestCollection> groupTestList = Lists.newArrayList(mongoTemplate.insert(list, GroupTestCollection.class));
     //   System.out.println(JSON.toJSON(groupTestList));
    }

    public void reduceGroup1() {
        GroupByResults<XObject> groupByResults = mongoTemplate.group("group_test_collection",
                GroupBy.key("x").initialDocument("{count:0}").reduceFunction("function(doc,prev){" +
                        "prev.count+=1}"), XObject.class);

        System.out.println(JSON.toJSONString(groupByResults));
        System.out.println(JSON.toJSONString(groupByResults.iterator()));
    }

    public void aggregate1() {
        Aggregation agg = Aggregation.newAggregation(
                project("tags"),
                Aggregation.unwind("tags"),
                Aggregation.group("tags").count().as("n"),
                project("n").and("tag").previousOperation(),
                Aggregation.sort(Sort.Direction.DESC, "n"));
        AggregationResults<TagCount> results = mongoTemplate.aggregate(agg, "article", TagCount.class);
        System.out.println(JSON.toJSONString(results.getMappedResults()));
    }

    public void aggregate2() {
        TypedAggregation<ZipInfo> aggregation = Aggregation.newAggregation(ZipInfo.class,
                Aggregation.group("state", "city")
                        .sum("population").as("pop"),
                Aggregation.sort(ASC, "pop", "state", "city"),
                Aggregation.group("state")
                        .last("city").as("biggestCity")
                        .last("pop").as("biggestPop")
                        .first("city").as("smallestCity")
                        .first("pop").as("smallestPop"),
                project()
                        .and("sate").previousOperation()
                        .and("biggestCity")
                        .nested(Aggregation.bind("name", "biggestCity").and("population", "biggestPop"))
                        .and("smallestCity")
                        .nested(Aggregation.bind("name", "smallestCity").and("population", "smallestPop")),
                Aggregation.sort(ASC, "state"));
        AggregationResults<ZipInfoStats> results = mongoTemplate.aggregate(aggregation, ZipInfoStats.class);
        System.out.println(JSON.toJSONString(results.getMappedResults()));
    }

    public void aggregate3() {
        TypedAggregation<ZipInfo> aggregation = Aggregation.newAggregation(ZipInfo.class,
                Aggregation.group("state")
                        .sum("population").as("totalPop"),
                Aggregation.sort(ASC, Aggregation.previousOperation(), "totalPop"),
                Aggregation.match(Criteria.where("totalPop").gte(200 * 100)));
        AggregationResults<StateStats> results = mongoTemplate.aggregate(aggregation, StateStats.class);
        System.out.println(JSON.toJSONString(results.getMappedResults()));
    }

    public void aggregate4() {
        TypedAggregation aggregation = Aggregation.newAggregation(Product.class,
                project("name", "netPrice")
                        .and("netPrice").plus(1).as("netPricePlus1")
                        .and("netPrice").minus(1).as("netPriceMinus1")
                        .and("netPrice").multiply(1.19).as("grossPrice")
                        .and("netPrice").divide(2).as("netPriceDiv2")
                        .and("spaceUnits").mod(2).as("spaceUnitsMod2"));
        AggregationResults<BasicDBObject> results = mongoTemplate.aggregate(aggregation, BasicDBObject.class);
        System.out.println(JSON.toJSONString(results.getMappedResults()));
    }

    public void aggregation5() {
        TypedAggregation<Product> aggregation = Aggregation.newAggregation(Product.class,
                project("name", "netPrice")
                        .andExpression("netPrice+1").as("netPricePlus1")
                        .andExpression("netPrice-1").as("netPriceMinus1")
                        .andExpression("netPrice /2").as("netPriceDiv2")
                        .andExpression("netPrice*1.19").as("grossPrice")
                        .andExpression("spaceUnits %2").as("spaceUnitsMod2")
                        .andExpression("(netPrice *0.8+1.2)*1.19").as("grossPriceIncludingDiscountAndCharge"));
        AggregationResults<BasicDBObject> results = mongoTemplate.aggregate(aggregation, BasicDBObject.class);
        System.out.println(JSON.toJSONString(results.getMappedResults()));
    }

    public void aggregation6() {
        double shippingCosts = 1.2;
        TypedAggregation<Product> aggregation = Aggregation.newAggregation(Product.class,
                project("name", "netPrice")
                        .andExpression("(netPrice*(spaceUnits-1)*[0])", shippingCosts).as("salesPrice"));
        AggregationResults<BasicDBObject> results = mongoTemplate.aggregate(aggregation, BasicDBObject.class);
        System.out.println(JSON.toJSONString(results.getMappedResults()));
    }

    public void aggregation7() {
        TypedAggregation<InventoryItem> aggregate = Aggregation.newAggregation(InventoryItem.class,
                Aggregation.project("item").and("discount")
                        .applyCondition(ConditionalOperators.Cond.newBuilder().when(Criteria.where("qty").gte(200))
                                .then(30)
                                .otherwise(20))
                        .and(ConditionalOperators.ifNull("description").then("Unspecified")).as("description"));
        AggregationResults<InventoryItemProjection> results = mongoTemplate.aggregate(aggregate, InventoryItemProjection.class);
        System.out.println(JSON.toJSONString(results.getMappedResults()));
    }

    public void aggregation8() {
        TypedAggregation<Book> aggregation = newAggregation(Book.class,
                Aggregation.project("title")
                        .and(ConditionalOperators.when(ComparisonOperators.valueOf("author")
                                .equalToValue("")).then("$$REMOVE").otherwiseValueOf("author")).as("author"));
        AggregationResults<BasicDBObject> results = mongoTemplate.aggregate(aggregation, BasicDBObject.class);
        System.out.println(JSON.toJSONString(results.getMappedResults()));
    }
}
